﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Pissing.cs" company="melcoprog">
//   Copyright (c) melcoprog. All rights reserved.
// </copyright>
// <summary>
//   The pissing.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace CreatureSheep.CreatureStates.Pissing
{
    using System;

    using Creature;

    /// <summary>
    /// The pissing.
    /// </summary>
    public class Pissing : ICreatureState
    {
        /// <summary>
        /// The gravity.
        /// </summary>
        private const double Gravity = 0.11;

        /// <summary>
        /// The frame count.
        /// </summary>
        private static int frameCount;

        /// <summary>
        /// The idle configuration.
        /// </summary>
        private readonly StateConfiguration configuration;

        /// <summary>
        /// The border.
        /// </summary>
        private readonly IBorder border;

        /// <summary>
        /// The pic.
        /// </summary>
        private double pic;

        /// <summary>
        /// The is on the ground.
        /// </summary>
        private bool isOnTheGround;

        /// <summary>
        /// Initializes a new instance of the <see cref="Pissing"/> class.
        /// </summary>
        /// <param name="repository">
        /// The repository.
        /// </param>
        /// <param name="border">
        /// The border.
        /// </param>
        public Pissing(IStateRepository repository, IBorder border)
        {
            this.isOnTheGround = false;
            this.border = border;
            this.configuration = repository.GetConfiguration();
        }

        /// <summary>
        /// The make step.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <returns>
        /// The <see cref="CreatureStep"/>.
        /// </returns>
        public CreatureStep MakeStep(Creature context)
        {
            var step = this.Move(context);
            return step;
        }

        #region

        /// <summary>
        /// The move single.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="dx">
        /// The delta x.
        /// </param>
        /// <param name="dy">
        /// The delta y.
        /// </param>
        private void MoveSingle(Creature context, double dx, double dy)
        {
            if (!this.border.StepIsBlocked(context, dx, 0, (int)this.configuration.Width, (int)this.configuration.Height))
            {
                context.X = context.X + dx;
            }

            if (!this.border.StepIsBlocked(context, 0, dy, (int)this.configuration.Width, (int)this.configuration.Height))
            {
                context.Y = context.Y + dy;
            }
            else if (context.Y + dy > (int)this.configuration.Height)
            {
                this.isOnTheGround = true;
            }
            else
            {
                context.AccelerationY = -context.AccelerationY;
                context.VelocityY = -context.VelocityY;
            }
        }

        /// <summary>
        /// The move.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="vx">
        /// The velocity x.
        /// </param>
        /// <param name="vy">
        /// The velocity y.
        /// </param>
        private void Move(Creature context, double vx, double vy)
        {
            var l = Math.Abs(Math.Abs(vx) > Math.Abs(vy) ? vx : vy);

            if (l > 0)
            {
                var dx = vx / l;
                var dy = vy / l;
                int i;
                for (i = 1; i <= (int)l; i++)
                {
                    this.MoveSingle(context, dx, dy);
                }

                var frac = l - (int)l;
                this.MoveSingle(context, dx * frac, dy * frac);
            }
        }

        /// <summary>
        /// The move.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <returns>
        /// The <see cref="CreatureStep"/>.
        /// </returns>
        private CreatureStep Move(Creature context)
        {
            if (!this.isOnTheGround)
            {
                context.AccelerationY = Gravity;

                context.VelocityX = (context.VelocityX * 0.98) + context.AccelerationX;
                context.VelocityY = (context.VelocityY * 0.98) + context.AccelerationY;

                this.Move(context, context.VelocityX, context.VelocityY);

                context.AccelerationX = 0;

                context.Speed = 0;
            }
            else
            {
                frameCount++;

                this.pic = this.pic + 0.1;
                if (this.pic > 5)
                {
                    this.pic = 3;
                }

                if (this.pic < 3)
                {
                    frameCount = 0;
                }
            }

            var image = this.configuration.LeftSprites[(int)this.pic].Key;
            var path = this.configuration.LeftSprites[(int)this.pic].Value;

            var step = new CreatureStep(image, context.X, context.Y, path);

            if (frameCount > 100 * 2)
            {
                context.AccelerationY = 0;
                context.VelocityY = 0;
                context.AccelerationX = 0;
                context.VelocityX = 0;
                this.pic = 0;
                frameCount = 0;
                this.isOnTheGround = false;

                context.SetState();
            }

            return step;
        }

        #endregion
    }
}
